using IGeekFan.AspNetCore.Knife4jUI;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using SwaggerDoc.Api;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Text;
using In66.Net.Consul.Extensions;
using In66.Net.Consul.Configuration;
using Microsoft.Extensions.Configuration;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Autofac.Extensions.DependencyInjection;
using Autofac;
using Autofac.Core;
using SwaggerDoc.Api.Validator;
using FluentValidation.AspNetCore;
using FluentValidation;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using In66.Net.Consul;
using AsyncFlow.Interfaces;
using Hangfire;
using SwaggerDoc.Api.AsyncFlowJob;
using AsyncFlow;
using Hangfire.MemoryStorage;
using AsyncFlow.ServiceCollection;

//CorsPolicyName
var CorsPolicyName = "";

//CorsEnableAllIPs
var CorsEnableAllIPs = string.Empty;

var builder = WebApplication.CreateBuilder(args);

#region json and validator

builder.Services.AddFluentValidationAutoValidation(conf =>
{
    //不传参数不报错
    conf.DisableDataAnnotationsValidation = true;
}).AddFluentValidationClientsideAdapters()
.AddValidatorsFromAssemblyContaining(typeof(Program));

builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
    //.net6Api响应:https://learn.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-6.0
    var builtInFactory = options.InvalidModelStateResponseFactory;

    options.InvalidModelStateResponseFactory = context =>
    {
        Dictionary<object, object> dic = new Dictionary<object, object>();

        context.ModelState.Keys.ForEach(p =>
        {
            ModelStateEntry modelStateEntry;

            context.ModelState.TryGetValue(p, out modelStateEntry);

            if (modelStateEntry != null)
                dic.Add(p, modelStateEntry.Errors.FirstOrDefault().ErrorMessage);
        });

        return new JsonResult(new { Code = 200, Msg = dic });
    };
})
//.AddNewtonsoftJson(options =>
//{
//    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
//    options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver();
//    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
//    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
//});
.AddJsonOptions(options =>
 {
     //编码
     options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(new TextEncoderSettings(UnicodeRanges.All));
     // 整齐打印
     options.JsonSerializerOptions.WriteIndented = true;
     // 允许结尾有逗号的不标准json
     options.JsonSerializerOptions.AllowTrailingCommas = true;
     // 允许在反序列化的时候原本应为数字的字符串（带引号的数字）转为数字
     options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
     // 反序列化不区分大小写
     options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
     // 命名
     options.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCasePolicy();
     //null字符串转为空字符串
     options.JsonSerializerOptions.Converters.Add(new EmptyStringConverter());
     //时间格式化
     options.JsonSerializerOptions.Converters.Add(new DateTimeConverter("yyyy-MM-dd HH:mm:ss"));
     //枚举传参变成字符串并且后台能正确转换成枚举值
     options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());

     //前端传 "" 和 null后端接收的值都转化成null
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<DateTime>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<DateTimeOffset>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<long>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<int>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<double>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<decimal>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<float>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<Guid>());
     options.JsonSerializerOptions.Converters.Add(new NullableConverter<bool>());
 });

#endregion

#region autofac

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
    builder.RegisterModule(new AutofacModuleRegister());
});

#endregion

#region swagger
//路径小写
builder.Services.AddRouting(options => options.LowercaseUrls = true);
//多版本控制
builder.Services.AddApiVersioning(options =>
{
    options.ReportApiVersions = true;

    options.AssumeDefaultVersionWhenUnspecified = true;

    options.DefaultApiVersion = new ApiVersion(1, 0);

    options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);

    //Header api-version
    //options.ApiVersionReader = new HeaderApiVersionReader("api-version");

    //Query api-version
    options.ApiVersionReader = new QueryStringApiVersionReader("api-version");

}).AddVersionedApiExplorer(option =>
{
    option.GroupNameFormat = "'v'V";
    option.AssumeDefaultVersionWhenUnspecified = true;
});

builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerConfigureOptions>();
builder.Services.AddSwaggerGen(options =>
{
    options.OperationFilter<OperationFilter>();
    options.SchemaFilter<SchemaFilter>();
    options.DocumentFilter<DocumentFilter>();
    options.OperationFilter<XCodeSamplesOperationFilter>();

    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"), true);

    #region 校验

    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "Value: Bearer {token}",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    options.AddSecurityRequirement(new OpenApiSecurityRequirement()
        {
          {
            new OpenApiSecurityScheme
            {
              Reference = new OpenApiReference
              {
                Type = ReferenceType.SecurityScheme,
                Id = "Bearer"
              },
              Scheme = "oauth2",
              Name = "Bearer",
              In = ParameterLocation.Header,
            },new List<string>()
          }
        });

    #endregion

});
#endregion

#region jwt

//var configuration = builder.Services.BuildServiceProvider().GetRequiredService<IConfiguration>();
//var tokenSection = configuration.GetSection(nameof(JwtOption));
//builder.Services.Configure<JwtOption>(tokenSection);
//var jwtOption = tokenSection.Get<JwtOption>();

//builder.Services.AddAuthentication(options =>
//{
//    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
//}).AddJwtBearer(options =>
//{
//    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
//    {
//        ValidateIssuer = true,
//        ValidateAudience = true,
//        ValidateLifetime = true,
//        ValidateIssuerSigningKey = true,
//        ValidIssuer = jwtOption.Issuer,
//        ValidAudience = jwtOption.Audience,
//        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOption.SecretKey))
//    };
//    //验证事件
//    options.Events = new JwtBearerEvents
//    {
//        // 在安全令牌已通过验证并生成 ClaimsIdentity 后调用
//        OnTokenValidated = (context) =>
//        {
//            var token = context.Request.Headers["Authorization"].ToString().Trim().Replace("Bearer ", "");

//            var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);
//            //var userService = context.HttpContext.RequestServices.GetService<UserService>();
//            //if (userService?.VerifyLogin() == false)
//            //{
//            //    context.Fail("登录超时或账号在其他地方登录");
//            //}

//            return Task.CompletedTask;
//        },
//        //收到消息
//        OnMessageReceived = context =>
//        {
//            var accessToken = context.Request.Query["access_token"];
//            var path = context.HttpContext.Request.Path;

//            if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/chatHub") &&
//                (context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream")))
//            {
//                context.Token = accessToken;
//            }
//            return Task.CompletedTask;
//        },
//        //OnChallenge
//        OnChallenge = context =>
//        {
//            var token = context.Request.Headers["Authorization"].ToString().Trim().Replace("Bearer ", "");

//            var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);

//            context.Response.Headers.Add("Token-Error", context.ErrorDescription);

//            return Task.CompletedTask;
//        },
//        //验证失败
//        OnAuthenticationFailed = context =>
//        {
//            var token = context.Request.Headers["Authorization"].ToString().Trim().Replace("Bearer ", "");

//            var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);

//            if (jwtToken.Issuer != jwtOption.Issuer)
//            {
//                context.Response.Headers.Add("Token-Error-Iss", "issuer is wrong!");
//            }

//            if (jwtToken.Audiences.FirstOrDefault() != jwtOption.Audience)
//            {
//                context.Response.Headers.Add("Token-Error-Aud", "Audience is wrong!");
//            }

//            // 如果过期，则把<是否过期>添加到，返回头信息中
//            if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
//            {
//                context.Response.Headers.Add("Token-Expired", "true");
//            }
//            return Task.CompletedTask;
//        }
//    };
//});

#endregion

#region consul

var ConsulSection = builder.Configuration.GetSection(ConsulConfig.Name);

var KestrelSection = builder.Configuration.GetSection(KestrelConfig.Name);

builder.Services.AddInfraConsul(ConsulSection, KestrelSection);

#endregion

#region cors
builder.Services.AddCors(c =>
{
    if (string.IsNullOrEmpty(CorsEnableAllIPs) == false)
    {
        c.AddPolicy(CorsPolicyName, policy =>
        {
            policy.WithOrigins(CorsEnableAllIPs.Split(','));
            policy.AllowAnyHeader();//Ensures that the policy allows any header.
            policy.AllowAnyMethod();
            policy.AllowCredentials();
        });
    }
    else
    {
        //允许任意跨域请求
        c.AddPolicy(CorsPolicyName, policy =>
        {
            policy.SetIsOriginAllowed((host) => true)
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials();
        });
    }
});
#endregion

#region AsyncFlow===>还没找到接入多版本Swagger的办法
// 配置 Hangfire
builder.Services.AddHangfire(config => config.UseMemoryStorage());
builder.Services.AddHangfireServer(options =>
{
});
builder.Services.AddAsyncFlow(options => options.UseMemoryCache());
// 注册业务逻辑类
builder.Services.AddTransient<DemoJob>(); 
#endregion

var app = builder.Build();

// 创建异步轮询 Web API
app.MapFlow<DemoJob, DemoRequest, DemoResponse>("demo");

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger(options =>
    {
        options.RouteTemplate = "swag/swagger/{documentName}/swagger.json";
    });

    #region SwaggerUI
    app.UseSwaggerUI(options =>
    {
        var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();

        foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
        {
            //配置swagger RoutePrefix 方便 自定义页面的配置
            options.RoutePrefix = "swag/swagger";

            options.SwaggerEndpoint($"/swag/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
        }
    });
    #endregion

    #region Knife4UI
    app.UseKnife4UI(c =>
    {
        c.RoutePrefix = "";

        var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();

        foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
        {
            c.SwaggerEndpoint($"/swag/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
        }
    });

    #endregion

    #region Redoc
    //Redoc
    app.UseReDoc(c =>
    {
    });
    #endregion
}

//跨域配置
app.UseCors(CorsPolicyName);

//认证
app.UseAuthentication();

//授权
app.UseAuthorization();

//consul 注册中心
app.UseRegistrationCenter();

app.MapControllers();

app.Run();
